﻿using System.Runtime.Caching;
using System.Collections.Specialized;

namespace SimpleORM.Extensions.MemoryCache
{
    /// <summary>
    /// MemoryCache帮助类（使用示例）
    /// </summary>
    public static class MemoryCacheHelper : object
    {
        /// <summary>
        /// 对象
        /// </summary>
        private static System.Runtime.Caching.MemoryCache _cache;

        #region 创建与销毁MemoryCache
        /// <summary>
        /// 创建新MemoryCache-使用默认配置项
        /// 程序退出后缓存会被清空
        /// </summary>
        /// <param name="name">MemoryCache名称</param>
        /// <param name="config">值集合</param>
        /// <param name="ignoreConfigSection">忽略配置Section</param>
        /// <returns></returns>
        public static System.Runtime.Caching.MemoryCache CreateMemoryCache()
        {
            _cache = System.Runtime.Caching.MemoryCache.Default;  //声明缓存类
            return _cache;
        }

        /// <summary>
        /// 创建新MemoryCache-通过配置项
        /// </summary>
        /// <param name="name">MemoryCache名称</param>
        /// <param name="config">值集合</param>
        /// <param name="ignoreConfigSection">忽略配置Section</param>
        /// <returns></returns>
        public static System.Runtime.Caching.MemoryCache NewMemoryCache(string name, NameValueCollection config, bool ignoreConfigSection) => _cache = new System.Runtime.Caching.MemoryCache(name, config, ignoreConfigSection);

        /// <summary>
        /// 创建一个 CacheEntryChangeMonitor 对象，响应指定缓存项的更改事件
        /// </summary>
        /// <param name="keys">需要响应的缓存项的枚举</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable<string> keys, string regionName = null) => _cache.CreateCacheEntryChangeMonitor(keys, regionName);

        /// <summary>
        /// 销毁MemoryCache
        /// </summary>
        public static void Dispose() => _cache.Dispose();

        /// <summary>
        /// 从缓存对象中移除指定百分比的缓存项
        /// </summary>
        /// <param name="percent"></param>
        /// <returns></returns>
        public static long Trim(int percent) => _cache.Trim(percent);
        #endregion 创建与销毁MemoryCache

        #region 获取MemoryCache配置
        /// <summary>
        /// 获取计算机上缓存可使用的内存量（以字节为单位）
        /// </summary>
        public static long CacheMemoryLimit => _cache.CacheMemoryLimit;
        /// <summary>
        /// 获取计算机上缓存可使用的物理内存的百分比
        /// </summary>
        public static long PhysicalMemoryLimit => _cache.PhysicalMemoryLimit;

        /// <summary>
        /// 获取缓存提供的功能的说明
        /// </summary>
        public static DefaultCacheCapabilities DefaultCacheCapabilities => _cache.DefaultCacheCapabilities;

        /// <summary>
        /// 获取在缓存更新其内存统计信息之前需等待的最大时间量
        /// </summary>
        public static TimeSpan PollingInterval => _cache.PollingInterval;

        /// <summary>
        /// 获取缓存的名称
        /// </summary>
        public static string Name => _cache.Name;
        #endregion 获取MemoryCache配置

        #region 存、取、删除值，检查是否存在值
        /// <summary>
        /// 确定缓存中是否存在某个缓存项
        /// </summary>
        /// <param name="key">要搜索的缓存项的唯一标识符</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static bool Contains(string key, string regionName = null) => _cache.Contains(key, regionName);

        #region 存值-复写原值
        /// <summary>
        /// 使用键和值将某个缓存项插入缓存中，并指定过期时间
        /// </summary>
        /// <param name="key">要插入的缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="absoluteExpiration">缓存项的固定的过期日期和时间</param>
        /// <param name="regionName">某个缓存集合</param>
        public static void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null) => _cache.Set(key, value, absoluteExpiration, regionName);

        /// <summary>
        /// 使用键和值将某个缓存项插入缓存中，并指定逐出选项（代替过期时间）
        /// </summary>
        /// <param name="key">要插入的缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="policy">一个包含该缓存项的逐出详细信息的对象。 此对象提供比简单绝对过期更多的逐出选项</param>
        /// <param name="regionName">某个缓存集合</param>
        public static void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
        {
            //CacheItemPolicy policy = new CacheItemPolicy();  //这个对象可以设置这个缓存的过期时间，和关联对象等等等。
            //policy.AbsoluteExpiration = DateTime.Now.AddMinutes(30);  //设置过期时间是当前时间+30分钟，那么30分钟后，这个缓存的项就会被移除
            _cache.Set(key, value, policy, regionName);
        }

        /// <summary>
        /// 使用 CacheItem 实例将某个缓存项插入缓存中，并指定逐出选项（代替过期时间）
        /// </summary>
        /// <param name="item">表示要插入的缓存项的对象</param>
        /// <param name="policy">一个包含该缓存项的逐出详细信息的对象。 此对象提供比简单绝对过期更多的逐出选项。</param>
        public static void Set(CacheItem item, CacheItemPolicy policy) => _cache.Set(item, policy);
        #endregion 存值-复写原值

        #region 存值-只新增，不复写原值
        /// <summary>
        /// 使用键和值将某个缓存项插入缓存中_不复写原值，并指定过期时间
        /// </summary>
        /// <param name="key">要插入的缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="absoluteExpiration">缓存项的固定的过期日期和时间</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns>如果插入成功，则为 true；如果缓存中已存在具有与 key 相同的键的项，则为 false。</returns>
        public static void Add(string key, object value, DateTimeOffset absoluteExpiration, string regionName = default) => _cache.Add(key, value, absoluteExpiration, regionName);

        /// <summary>
        /// 使用键和值将某个缓存项插入缓存中_不复写原值，并指定逐出选项（代替过期时间）
        /// </summary>
        /// <param name="key">要插入的缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="policy">一个包含该缓存项的逐出详细信息的对象。 此对象提供比简单绝对过期更多的逐出选项</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns>如果插入成功，则为 true；如果缓存中已存在具有与 key 相同的键的项，则为 false。</returns>
        public static void Add(string key, object value, CacheItemPolicy policy, string regionName = null) => _cache.Add(key, value, policy, regionName);

        /// <summary>
        /// 使用 CacheItem 实例将某个缓存项插入缓存中_不复写原值，并指定逐出选项（代替过期时间）
        /// </summary>
        /// <param name="item">表示要插入的缓存项的对象</param>
        /// <param name="policy">一个包含该缓存项的逐出详细信息的对象。 此对象提供比简单绝对过期更多的逐出选项。</param>
        /// <returns>如果插入成功，则为 true；如果缓存中已存在具有与 key 相同的键的项，则为 false。</returns>
        public static bool Add(CacheItem item, CacheItemPolicy policy) => _cache.Add(item, policy);

        /// <summary>
        /// 使用键和值将某个缓存项插入缓存中_不复写原值，并指定过期时间
        /// </summary>
        /// <param name="key">要插入的缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="absoluteExpiration">缓存项的固定的过期日期和时间</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns>如果存在具有相同键的缓存项，则为现有的缓存项；否则为 null</returns>
        public static object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = default) => _cache.AddOrGetExisting(key, value, absoluteExpiration, regionName);

        /// <summary>
        /// 使用键和值将某个缓存项插入缓存中_不复写原值，并指定逐出选项（代替过期时间）
        /// </summary>
        /// <param name="key">要插入的缓存项的唯一标识符</param>
        /// <param name="value">该缓存项的数据</param>
        /// <param name="policy">一个包含该缓存项的逐出详细信息的对象。 此对象提供比简单绝对过期更多的逐出选项</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns>如果存在具有相同键的缓存项，则为现有的缓存项；否则为 null</returns>
        public static object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = default) => _cache.AddOrGetExisting(key, value, policy, regionName);

        /// <summary>
        /// 使用 CacheItem 实例将某个缓存项插入缓存中_不复写原值，并指定逐出选项（代替过期时间）
        /// </summary>
        /// <param name="item">表示要插入的缓存项的对象</param>
        /// <param name="policy">一个包含该缓存项的逐出详细信息的对象。 此对象提供比简单绝对过期更多的逐出选项。</param>
        /// <returns>如果存在具有相同键的缓存项，则为现有的缓存项；否则为 null</returns>
        public static CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy) => _cache.AddOrGetExisting(item, policy);
        #endregion 存值-只新增，不复写原值

        #region 取值
        /// <summary>
        /// 返回某个缓存中的缓存项总数
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        public static long GetCount(string regionName = default) => _cache.GetCount(regionName);

        /// <summary>
        /// 获取某个缓存已使用的内存量（以字节为单位）
        /// </summary>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static long GetLastSize(string regionName = default) => _cache.GetLastSize(regionName);

        /// <summary>
        /// 从缓存中读取某缓存项
        /// </summary>
        /// <param name="key">要获取的缓存项的唯一标识符</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static object Get(string key, string regionName = default) => _cache.Get(key, regionName);

        /// <summary>
        /// 从缓存中读取某缓存项_返回CacheItem
        /// </summary>
        /// <param name="key">要获取的缓存项的唯一标识符</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static CacheItem GetCacheItem(string key, string regionName = default) => _cache.GetCacheItem(key, regionName);

        /// <summary>
        /// 获取与指定的键对应的一组缓存项
        /// </summary>
        /// <param name="keys">要获取的缓存项的唯一标识符</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static IDictionary<string, object> GetValues(IEnumerable<string> keys, string regionName = default) => _cache.GetValues(keys, regionName);

        /// <summary>
        /// 获取与指定的键对应的一组缓存项
        /// </summary>
        /// <param name="regionName">某个缓存集合</param>
        /// <param name="keys">要获取的缓存项的唯一标识符</param>
        /// <returns></returns>
        public static IDictionary<string, object> GetValues(string regionName, params string[] keys) => _cache.GetValues(regionName, keys);
        #endregion 取值

        #region 删除
        /// <summary>
        /// 从缓存中移除某个缓存项
        /// </summary>
        /// <param name="key">要搜索的缓存项的唯一标识符</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static object Remove(string key, string regionName = null) => _cache.Remove(key, regionName);

        /// <summary>
        /// 使用原因从缓存中删除缓存项
        /// </summary>
        /// <param name="key">要移除的缓存项的唯一标识符</param>
        /// <param name="reason">删除项的原因</param>
        /// <param name="regionName">某个缓存集合</param>
        /// <returns></returns>
        public static object Remove(string key, CacheEntryRemovedReason reason, string regionName = null) => Remove(key, reason, regionName);
        #endregion 删除
        #endregion 存、取、删除值，检查是否存在值
    }

}
